﻿namespace Refract.Event
{
    using System;
    using System.ComponentModel.Composition;

    using Refract.Composition;

    /// <summary>
    /// A leak safe function reference type.  To be used with QuerySubscription.
    /// </summary>
    /// <typeparam name="TParam">The type of the param.</typeparam>
    /// <typeparam name="TResult">The type of the result.</typeparam>
    public class Query<TParam, TResult>
    {
        #region Fields

        private WeakReference _functionReference;

        #endregion Fields

        #region Constructors

        public Query(string name)
        {
            Container.Current.ComposeExportedValue(QualifiedName(name), this);
        }

        #endregion Constructors

        #region Properties

        public bool IsSubscribed
        {
            get { return _functionReference != null && _functionReference.IsAlive; }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Invokes the query's referenced function.
        /// </summary>
        /// <param name="parameter">The parameter.</param>
        /// <returns></returns>
        public TResult Invoke(TParam parameter)
        {
            if (!_functionReference.IsAlive) return default(TResult);
            var function = _functionReference.Target as Func<TParam, TResult>;
            if(function == null)
            {
                return default(TResult);
            }
            return function(parameter);
        }

        /// <summary>
        /// Returns a qualified query name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        internal static string QualifiedName(string name)
        {
            return typeof(Query).FullName + "." + name;
        }

        /// <summary>
        /// Subscribes to the specified function.  
        /// </summary>
        /// <remarks>
        /// Only one function can be subscribed to at one time.  Subsequent subscriptions will replace previous ones.
        /// </remarks>
        /// <param name="function">The function.</param>
        internal void Subscribe(Func<TParam, TResult> function)
        {
            _functionReference = new WeakReference(function);
        }

        #endregion Methods
    }

    /// <summary>
    /// A leak safe function reference type.  To be used with QuerySubscription.
    /// </summary>
    public class Query : Query<object, object>
    {
        #region Constructors

        public Query(string name)
            : base(name)
        {
        }

        #endregion Constructors
    }
}